home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / EARCD / comm / misc / New8n1.lha / 8n1_000.s next >
Text File  |  1996-12-14  |  61KB  |  2,012 lines

  1. ********************************************************************************
  2. **                                          **
  3. **  Name       : 8n1_000.s                              **
  4. **  Copyright  : © Copyright 96                           **
  5. **  Author     : Iain Barclay                              **
  6. **  Created    : 02 Dec 96                              **
  7. **  Version    : 37.26                                  **
  8. **                                          **
  9. ********************************************************************************
  10.      ;
  11.      ;      SNMA specific options
  12.      ;
  13.      IFD      SNMA
  14.      ;
  15.      CPU      M68010
  16.      ;
  17.      SNMAOPT  Q,A,M,T,E-
  18.      ;
  19.      ELSE
  20.      IFD PHXASS
  21.      machine 68010
  22.      OPT !
  23.      ENDC
  24.      ENDC
  25.      ;
  26.      ;
  27. DEBUG     SET    0
  28. NEWCODE  SET    1
  29. EOFCODE  SET    1
  30. SETDSR     SET    0
  31. NCOMM     SET    0
  32.      ;
  33.      ;
  34.      ;
  35.      SECTION  text,CODE
  36.      ;
  37.      ;
  38.      ;
  39. DEVICES_SERIAL_I_OBSOLETE  EQU        1
  40.      ;
  41.      ;
  42.      ;
  43.      INCLUDE  "exec/lists.i"
  44.      INCLUDE  "exec/memory.i"
  45.      INCLUDE  "exec/resident.i"
  46.      INCLUDE  "exec/devices.i"
  47.      INCLUDE  "exec/execbase.i"
  48.      INCLUDE  "exec/io.i"
  49.      INCLUDE  "exec/ports.i"
  50.      INCLUDE  "exec/errors.i"
  51.      INCLUDE  "exec/initializers.i"
  52.      INCLUDE  "intuition/preferences.i"
  53.      INCLUDE  "devices/timer.i"
  54.      INCLUDE  "devices/serial.i"
  55.      INCLUDE  "hardware/custom.i"
  56.      INCLUDE  "hardware/cia.i"
  57.      INCLUDE  "hardware/intbits.i"
  58.      INCLUDE  "hardware/adkbits.i"
  59.      INCLUDE  "resources/misc.i"
  60.      INCLUDE  "exec/alerts.i"
  61.      INCLUDE  "exec/macros.i"
  62.      INCLUDE  "8n1.device_rev.i"
  63.      ;
  64.      ;      Define hardware references
  65.      ;
  66.      XREF      _custom
  67.      XREF      _intena,_intenar,_intreq,_intreqr
  68.      XREF      _ciab,_ciabpra
  69.      XREF      _serper,_serdat,_serdatr
  70.      XREF      _adkcon,_adkconr
  71.      ;
  72.      ;      Exec Functions
  73.      ;
  74.      XREF      _LVORemDevice,_LVOOpenDevice,_LVOCloseDevice
  75.      XREF      _LVOSupervisor
  76.      XREF      _LVOAllocMem,_LVOFreeMem,_LVOCopyMem
  77.      XREF      _LVOReplyMsg
  78.      XREF      _LVOSendIO,_LVOAbortIO
  79.      XREF      _LVODisable,_LVOEnable
  80.      XREF      _LVOFindName
  81.      XREF      _LVOOpenResource
  82.      XREF      _LVOAddIntServer,_LVORemIntServer
  83.      XREF      _LVOSetIntVector
  84.      XREF      _LVOAlert
  85.      XREF      _LVOOpenLibrary,_LVOCloseLibrary
  86.      ;
  87.      ;      Misc Resource Functions
  88.      ;
  89.      XREF      _LVOAllocMiscResource,_LVOFreeMiscResource
  90.      ;
  91.      ;      Intuition Functions
  92.      ;
  93.      XREF      _LVOGetPrefs
  94.      ;
  95.      ;      Mask used to get rid of the printer bits.
  96.      ;
  97. PRTMASK  EQU      (CIAF_PRTRPOUT|CIAF_PRTRBUSY)
  98.      ;
  99.      ;      Autovector offsets
  100.      ;
  101. LVL1VEC  EQU      (1-1)*4+$64
  102. LVL5VEC  EQU      (5-1)*4+$64
  103.      ;
  104.      ;      Device base
  105.      ;
  106.      STRUCTURE Base8n1,LIB_SIZE
  107.      UBYTE      vb_SaveDDRA
  108.      UBYTE      vb_SavePRA
  109.      APTR      vb_MiscBase
  110.      APTR      vb_OldLevel1
  111.      APTR      vb_OldLevel5
  112.      ULONG      vb_SegList
  113.      ULONG      vb_DefBaud
  114.      ULONG      vb_DefRBufLen
  115.      ULONG      vb_CurRBuf
  116.      ULONG      vb_CurRBufLen
  117.      ULONG      vb_CurBaud
  118.      UBYTE      vb_SerFlags
  119.      UBYTE      vb_Initialized
  120.      LABEL      sizeof_Base8n1
  121.      ;
  122.      ;
  123.      ;
  124. DISABLE  MACRO
  125.      IFNC      '\1',''
  126.      move.w   #INTF_\1,_intena
  127.      ELSE
  128.      jsr      _LVODisable(a6)
  129.      ENDC
  130.      ENDM
  131.      ;
  132. ENABLE     MACRO
  133.      IFNC      '\1',''
  134.      move.w   #INTF_SETCLR|INTF_\1,_intena
  135.      ELSE
  136.      jsr      _LVOEnable(a6)
  137.      ENDC
  138.      ENDM
  139.      ;
  140.      ;
  141.      ;
  142. PUTDEBUG macro      ;[msg]
  143.      ifge      DEBUG-2
  144.      movem.l  a0/a1/d0/d1,-(sp)
  145.      lea      (.msg\@,pc),a0  ;Point to static format string
  146.      lea      (4*4,sp),a1      ;Point to args
  147.      XREF      DPutFmt
  148.      bsr      DPutFmt
  149.      movem.l  (sp)+,d0/d1/a0/a1
  150.      bra.b      .end\@
  151.  
  152. .msg\@     dc.b      \1,10,0
  153.      CNUL      0,4
  154. .end\@
  155.      endc
  156.      endm
  157.      ;
  158.      ;
  159.      ;
  160. DEBUG1     MACRO
  161.      IFNE       DEBUG
  162.      XREF      _SendText
  163.      move.l   \2,-(sp)
  164.      pea.l      debug1s\@$
  165.      pea.l      Name
  166.      jsr      _SendText(pc)
  167.      lea.l      12(sp),sp
  168.      bra.b      debug1x\@$
  169. debug1s\@$:
  170.      dc.b      \1,0
  171.      CNOP      0,2
  172. debug1x\@$:
  173.      ENDC
  174.      ENDM
  175. DEBUG0     MACRO
  176.      XREF      _SendText
  177.      pea.l      debug1s\@$
  178.      pea.l      Name
  179.      jsr      _SendText(pc)
  180.      addq      #8,sp
  181.      bra.b      debug1x\@$
  182. debug1s\@$:
  183.      dc.b      \1,0
  184. debug1x\@$:
  185.      ENDM
  186.  
  187. DEBUGIO  MACRO
  188.      IFNE      DEBUG
  189.      lea.l      \1,a0
  190.      jsr      printIO
  191.      ENDC
  192.      ENDM
  193.      ;
  194.      ;
  195.      ;
  196. Start:
  197.      moveq      #-1,d0                  ; set return code
  198.      rts                          ; return
  199.      ;
  200.      ;      RamLib looks for this romtag
  201.      ;
  202. ROMTag     DC.W      RTC_MATCHWORD               ; RT_MATCHWORD
  203.      DC.L      ROMTag                  ; RT_MATCHTAG
  204.      DC.L      ENDTag                  ; RT_ENDSKIP
  205.      DC.B      RTF_AUTOINIT                  ; RT_FLAGS
  206.      DC.B      VERSION                  ; RT_VERSION
  207.      DC.B      NT_DEVICE                  ; RT_TYPE
  208.      DC.B      0                      ; RT_PRI
  209.      DC.L      Name                      ; RT_NAME
  210.      DC.L      IdString                  ; RT_IDSTRING
  211.      DC.L      Init                      ; RT_INIT
  212.      ;
  213.      ;      Perform device initialization
  214.      ;
  215. InitRoutine:
  216.      exg      d0,a0                   ; swap seglist and base
  217.      move.l   d0,vb_SegList(a0)              ; store seglist in base
  218.      move.l   a6,SysBase                  ; store in global storage
  219.      exg      a0,d0                   ; swap them back
  220.      rts                          ; return
  221.      ;
  222.      ;
  223.      ;
  224. dev_Open:
  225.      DEBUG1   "Devstart %lx",#Start
  226.      move.l   a5,-(sp)                  ; save registers
  227.      movea.l  a6,a5                   ; save base
  228.      movea.l  SysBase(pc),a6              ; get ExecBase
  229.      ;
  230.      tst.l      d0                      ; unit 0 specified?
  231.      bne.b      50$                      ; nope, error (who cares?)
  232.      ;
  233.      tst.w      LIB_OPENCNT(a5)              ; currently open?
  234.      bne.b      10$                      ; yep, go process
  235.      ;
  236.      move.b   IO_SERFLAGS(a1),vb_SerFlags(a5)     ; save flags
  237.      ;
  238.      tst.b      vb_Initialized(a5)              ; already initialized?
  239.      bne.b      40$                      ; yep, skip initialization
  240.      ;
  241.      bsr      initResources               ; go alloc resources
  242.      tst.l      d0                      ; initialized?
  243.      bne.b      50$                      ; nope, error
  244.      ;
  245.      bra.b      40$                      ; go exit
  246.      ;
  247. 10$     moveq      #SerErr_DevBusy,d0              ; preset error status
  248.      btst      #SERB_SHARED,vb_SerFlags(a5)          ; opened shared?
  249.      beq.b      50$                      ; nope, error
  250.      btst      #SERB_SHARED,IO_SERFLAGS(a1)          ; requesting shared?
  251.      beq.b      50$                      ; nope, error
  252.      ;
  253.      ;      Initialize I/O request
  254.      ;
  255. 40$     moveq      #8,d0                   ; get char size
  256.      move.b   d0,IO_READLEN(a1)              ; set read length
  257.      move.b   d0,IO_WRITELEN(a1)              ; set write length
  258.      moveq      #1,d0                   ; get stop bits
  259.      move.b   d0,IO_STOPBITS(a1)              ; set stop bits
  260.      move.b   IO_SERFLAGS(a1),d0
  261.      ori.b      #SERF_XDISABLED|SERF_RAD_BOOGIE|SERF_QUEUEDBRK|SERF_7WIRE,d0 ;flags
  262.      andi.b   #~(SERF_PARTY_ODD|SERF_PARTY_ON),d0 ; not used
  263.      move.b   d0,IO_SERFLAGS(a1)
  264.      move.l   vb_CurBaud(a5),IO_BAUD(a1)          ; set baud
  265.      move.l   vb_CurRBufLen(a5),IO_RBUFLEN(a1)    ; set read buffer length
  266.      ;
  267.      addq.w   #1,LIB_OPENCNT(a5)              ; incr open count
  268.      andi.b   #~(1<<LIBB_DELEXP),LIB_FLAGS(a5)    ; clear expunge bit
  269.      moveq      #0,d0                   ; no error
  270.      ;
  271. 50$     move.b   d0,IO_ERROR(a1)              ; store error code
  272.      movea.l  a5,a6                   ; restore base
  273.      move.l   (sp)+,a5                  ; restore registers
  274.      rts                          ; return
  275.      ;
  276.      ;      Attempt to allocate one of the serial resources.
  277.      ;
  278. allocResource:
  279.      move.l   a6,-(sp)                  ; save base pointer
  280.      move.l   d0,-(sp)                  ; save unit
  281.      lea.l      Name(pc),a1                  ; get lock name
  282.      move.l   vb_MiscBase(a5),a6              ; get MiscBase
  283.      jsr      _LVOAllocMiscResource(a6)          ; go allocate it
  284.      tst.l      d0                      ; did we get it?
  285.      beq.b      20$                      ; yep, branch
  286.      ;
  287.      ;      It's in use, so we try to locate the device using the string
  288.      ;      returned and attempt to remove it.
  289.      ;
  290.      movea.l  SysBase(pc),a6              ; get ExecBase
  291.      ;
  292.      movea.l  d0,a1                   ; get ptr to serial name
  293.      lea.l      DeviceList(a6),a0              ; get ptr to device list
  294.      jsr      _LVOFindName(a6)              ; go find it
  295.      tst.l      d0                      ; found?
  296.      beq.b      10$                      ; nope, branch
  297.      ;
  298.      movea.l  d0,a1                   ; xfer device ptr
  299.      jsr      _LVORemDevice(a6)              ; remove it
  300.      ;
  301.      ;      We then retry the allocate.
  302.      ;
  303. 10$     move.l   (sp),d0                  ; get unit
  304.      lea.l      Name(pc),a1                  ; get lock name
  305.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  306.      jsr      _LVOAllocMiscResource(a6)          ; go allocate it
  307.      ;
  308. 20$     addq.l   #4,sp                   ; restore stack ptr
  309.      movea.l  (sp)+,a6                  ; restore base ptr
  310.      rts                          ; return
  311.      ;
  312.      ;
  313.      ;
  314. initResources:
  315.      move.l   a1,-(sp)                  ; save register
  316.      ;
  317.      lea.l      miscresource(pc),a1              ; ptr to resource name
  318.      jsr      _LVOOpenResource(a6)              ; go open it
  319.      move.l   d0,vb_MiscBase(a5)              ; save base
  320.      ;
  321.      moveq      #MR_SERIALPORT,d0              ; set unit number
  322.      bsr.b      allocResource               ; go allocate it
  323.      tst.l      d0                      ; did we get it?
  324.      bne.b      20$                      ; nope, error
  325.      ;
  326.      moveq      #MR_SERIALBITS,d0              ; set unit number
  327.      bsr.b      allocResource               ; go allocate it
  328.      tst.l      d0                      ; did we get it?
  329.      bne.b      10$                      ; nope, error
  330.      ;
  331.      bsr      getPrefs                  ; get default preferences
  332.      tst.l      d0                      ; got 'em?
  333.      beq.b      30$                      ; yep, branch
  334.      ;
  335.      moveq      #MR_SERIALBITS,d0              ; set unit
  336.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  337.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  338.      ;
  339. 10$     moveq      #MR_SERIALPORT,d0              ; set unit
  340.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  341.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  342.      movea.l  SysBase(pc),a6              ; restore ExecBase
  343.      ;
  344. 20$     moveq      #SerErr_DevBusy,d0              ; set error status
  345.      bra      40$                      ; go return
  346.      ;
  347. 30$     moveq      #0,d1                   ; clear flags
  348.      moveq      #UNIT_VBLANK,d0              ; set unit
  349.      lea.l      timerReq(pc),a1              ; ptr to timer request
  350.      lea.l      timerdevice(pc),a0              ; ptr to device name
  351.      jsr      _LVOOpenDevice(a6)              ; go open it
  352.      ;
  353.      DISABLE                      ; disable interrupts
  354.      ;
  355.      lea.l      _ciab,a1                  ; get ptr to ciab
  356.      move.b   ciaddra(a1),d0
  357.      move.b   d0,vb_SaveDDRA(a5)              ; save DDR value
  358.      andi.b   #PRTMASK,d0                  ; make serial bits input
  359.      move.b   (a1),d1                  ; ciapra(a1)
  360.      ori.b      #CIAF_COMDTR|CIAF_COMRTS,d0          ; make DTR/RTS output
  361.      move.b   d1,vb_SavePRA(a5)              ; save PR value
  362.      andi.b   #CIAF_COMDTR|CIAF_COMRTS|PRTMASK,d0 ; turn on DTR/RTS
  363.      move.b   d0,ciaddra(a1)
  364.      andi.b   #CIAF_COMCTS|CIAF_COMDSR|PRTMASK,d1 ; make CTS/DSR input
  365.      move.b   d1,(a1)                  ; ciapra(a1)
  366.      ;
  367.      moveq      #INTB_PORTS,d0              ; get interrupt number
  368.      lea.l      VBInterrupt(pc),a1              ; get interrupt ptr
  369.      jsr      _LVOAddIntServer(a6)              ; add it to the list
  370.      ;
  371.      bsr      getVBR                  ; get vector base (in A0)
  372.      ;
  373.      move.l   LVL1VEC(a0),vb_OldLevel1(a5)          ; save original vector
  374.      lea.l      level1(pc),a1               ; get new vector ptr
  375.      move.l   a1,LVL1VEC(a0)              ; set new vector
  376.      ;
  377.      move.l   LVL5VEC(a0),vb_OldLevel5(a5)          ; save original vector
  378.      lea.l      level5(pc),a1               ; get new vector ptr
  379.      move.l   a1,LVL5VEC(a0)              ; set new vector
  380.      ;
  381.      lea.l      _custom,a1                  ; get ptr to custom chips
  382.      move.w   #INTF_RBF|INTF_TBE,intreq(a1)       ; clear pending interrupts
  383.      move.w   #INTF_SETCLR|INTF_RBF|INTF_TBE,intena(a1) ; enable RBF & TBE
  384.      ;
  385.      addq.b   #1,vb_Initialized(a5)           ; set flag
  386.      moveq      #0,d0                   ; set good status
  387.      ;
  388.      ENABLE                       ; enable interrupts
  389.      ;
  390. 40$     movea.l  (sp)+,a1                  ; restore register
  391.      rts                          ; return
  392.      ;
  393.      ;      Get system preferences
  394.      ;
  395. getPrefs:
  396.      move.l   a1,-(sp)                  ; save registers
  397.      ;
  398.      lea.l      intuitlib(pc),a1              ; ptr to library name
  399.      moveq      #0,d0                   ; can't use OldOpenLibrary as this will not be supported.
  400.      jsr      _LVOOpenLibrary(a6)              ; go open it (any version)
  401.      movea.l  d0,a6                   ; get intuition base
  402.      ;
  403.      move.l   #(pf_SerParShk+3)&$fffffffc,d0      ; size we need (aligned)
  404.      suba.l   d0,sp                   ; reserve space
  405.      ;
  406.      movea.l  sp,a0                   ; set data area ptr
  407.      jsr      _LVOGetPrefs(a6)              ; get preferences
  408.      ;
  409.      movea.l  a6,a1                   ; get intuition base
  410.      movea.l  SysBase(pc),a6              ; restore ExecBase
  411.      jsr      _LVOCloseLibrary(a6)              ; close it
  412.      ;
  413.      moveq      #$0f,d1                  ; set mask
  414.      and.b      pf_SerStopBuf(sp),d1              ; get bufsize index
  415.      addq.l   #8,d1                   ; calc shift value
  416.      moveq      #2,d0                   ; get 1<<1
  417.      lsl.l      d1,d0                   ; get default bufsize
  418.      move.l   d0,vb_DefRBufLen(a5)              ; and store
  419.      ;
  420.      moveq      #0,d1                   ; clear upper half
  421.      move.w   pf_BaudRate(sp),d1              ; get baud rate
  422.      add.l      d1,d1                   ; generate offset
  423.      move.w   baudTable(pc,d1.w),d1           ; get default baud
  424.      move.l   d1,vb_DefBaud(a5)              ; and store
  425.      ;
  426.      bsr      internalReset               ; go init baud and buffer
  427.      ;
  428.      lea.l      (pf_SerParShk+3)&$fffffffc(sp),sp   ; restore stack
  429.      movea.l  (sp)+,a1                  ; restore registers
  430.      rts                          ; return ( status in D0 )
  431.      ;
  432.      ;      Preferences baud lookup table
  433.      ;
  434. baudTable:
  435.      dc.w      112,300,1200,2400,4800,9600,19200,31250,38400,57600,62400,64800
  436.      ;
  437.      ;      Set exception vectors
  438.      ;
  439. getVBR:
  440.      move.l   a5,-(sp)                  ; save registers
  441.      suba.l   a0,a0                   ; ptr to vector base (68000)
  442.      btst      #AFB_68010,AttnFlags+1(a6)          ; 68010 or higher?
  443.      beq.b      10$                      ; nope, go set vector
  444.      lea.l      20$(pc),a5                  ; ptr to routine
  445.      jsr      _LVOSupervisor(a6)              ; get into supervisor state
  446. 10$     movea.l  (sp)+,a5                  ; restore register
  447.      rts                          ; return
  448. 20$     movec.l  vbr,a0                  ; get vector base
  449.      rte                          ; return
  450.      ;
  451.      ;
  452.      ;
  453. freeResources:
  454.      move.l   a1,-(sp)                  ; save registers
  455.      ;
  456.      DISABLE                      ; disable interrupts
  457.      ;
  458.      bsr.b      getVBR                  ; get vector base (in A0)
  459.      ;
  460.      moveq      #1,d0                   ; set not restored code
  461.      ;
  462.      lea.l      level1(pc),a1               ; get our vector ptr
  463.      cmpa.l   LVL1VEC(a0),a1              ; do they match?
  464.      bne      10$                      ; nope, can't restore
  465.      ;
  466.      lea.l      level5(pc),a1               ; get our vector ptr
  467.      cmpa.l   LVL5VEC(a0),a1              ; do they match?
  468.      bne      10$                      ; nope, can't restore
  469.      ;
  470.      move.l   vb_OldLevel1(a5),LVL1VEC(a0)          ; restore original vector
  471.      move.l   vb_OldLevel5(a5),LVL5VEC(a0)          ; restore original vector
  472.      ;
  473.      moveq      #INTB_PORTS,d0              ; get interrupt number
  474.      lea.l      VBInterrupt(pc),a1              ; get interrupt ptr
  475.      jsr      _LVORemIntServer(a6)              ; remove it from the list
  476.      ;
  477.      lea.l      _custom,a0
  478.      move.w   #INTF_RBF|INTF_TBE,d0           ; indicate serial interrupts
  479.      move.w   d0,intena(a0)               ; disable interrupts
  480.      move.w   d0,intreq(a0)               ; clear pending interrupts
  481.      ;
  482.      bsr      freeBuf                  ; free allocated buffers
  483.      ;
  484.      lea.l      _ciab,a0                  ; get pointer to ciab
  485.      move.b   ciaddra(a0),d0              ; get DDR value
  486.      andi.b   #PRTMASK,d0                  ; save printer bits
  487.      ori.b      #~PRTMASK,d0                  ; set serial bits to output
  488.      move.b   d0,ciaddra(a0)              ; store value
  489.      ;
  490.      move.b   (a0),d0                  ; get PR value ( ciapra(a0) )
  491.      andi.b   #PRTMASK,d0                  ; mask out serial bits
  492.      move.b   vb_SavePRA(a5),d1              ; get saved value
  493.      andi.b   #~PRTMASK,d1                  ; mask out printer bits
  494.      or.b      d1,d0                   ; combine the two
  495.      move.b   d0,(a0)                  ; and store ( ciapra(a0) )
  496.      ;
  497.      move.b   ciaddra(a0),d0              ; get DDR value
  498.      andi.b   #PRTMASK,d0                  ; mask out serial bits
  499.      move.b   vb_SaveDDRA(a5),d1              ; get saved value
  500.      andi.b   #~PRTMASK,d1                  ; mask out printer bits
  501.      or.b      d1,d0                   ; combine the two
  502.      move.b   d0,ciaddra(a0)              ; and store
  503.      ;
  504.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  505.      jsr      _LVOCloseDevice(a6)              ; go close it
  506.      ;
  507.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  508.      moveq      #MR_SERIALBITS,d0              ; set unit
  509.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  510.      ;
  511.      moveq      #MR_SERIALPORT,d0              ; set unit
  512.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  513.      movea.l  SysBase(pc),a6              ; restore ExecBase
  514.      ;
  515.      ENABLE                       ; enable interrupts
  516.      ;
  517.      subq.b   #1,vb_Initialized(a5)           ; clear flag
  518.      moveq      #0,d0                   ; free up everything
  519.      ;
  520. 10$     movea.l  (sp)+,a1                  ; restore registers
  521.      rts                          ; return
  522.      ;
  523.      ;      Device Close routine
  524.      ;
  525. dev_Close:
  526.      ;
  527.      moveq      #-1,d0                  ; invalidate
  528.      move.l   d0,IO_DEVICE(a1)              ;   device
  529.      ;
  530.      subq.w   #1,LIB_OPENCNT(a6)              ; decr open count
  531.      bne.b      dev_Null                  ; still open? yep, branch
  532.      ;
  533.      move.l   a5,-(sp)                  ; save registers
  534.      movea.l  a6,a5                   ; save base
  535.      movea.l  SysBase(pc),a6              ; get ExecBase
  536.      ;
  537.      bsr      freeResources               ; free allocated resources
  538.      ;
  539.      movea.l  a5,a6                   ; restore base
  540.      movea.l  (sp)+,a5                  ; restore registers
  541.      ;
  542.      tst.l      d0                      ; freed?
  543.      bne.b      dev_Null                  ; nope, can't expunge, exit
  544.      ;
  545.      clr.b      vb_SerFlags(a6)              ; clear flags
  546.      ;
  547.      btst      #LIBB_DELEXP,LIB_FLAGS(a6)          ; delayed expunge set?
  548.      beq.b      dev_Null                  ; nope, go exit
  549.      ;
  550.      ;      Device Expunge routine (also fall through from dev_Close)
  551.      ;
  552. dev_Expunge:
  553.      ori.b      #1<<LIBB_DELEXP,LIB_FLAGS(a6)       ; Set expunge flag
  554.      tst.w      LIB_OPENCNT(a6)              ; currently open?
  555.      bne.b      dev_Null                  ; yep, so just exit
  556.      ;
  557.      move.l   vb_SegList(a6),d0              ; get seglist ptr
  558.      move.l   d0,-(sp)                  ; save registers (save D0!)
  559.      ;
  560.      movea.l  a6,a1                   ; get base
  561.      ; This is the REMOVE macro
  562.      move.l   (a1)+,a0
  563.      move.l   (a1),a1                  ; LN+PRED
  564.      move.l   a0,(a1)
  565.      move.l   a1,LN_PRED(a0)
  566.      ;
  567.      movea.l  a6,a1                   ; get base
  568.      moveq      #0,d0                   ; clear work
  569.      move.w   LIB_NEGSIZE(a6),d0              ; calculate
  570.      suba.w   d0,a1                   ;   memory address
  571.      add.w      LIB_POSSIZE(a6),d0              ;     and size
  572.      move.l   a6,-(sp)                  ; save registers
  573.      movea.l  SysBase(pc),a6              ; get ExecBase
  574.      jsr      _LVOFreeMem(a6)              ; free it
  575.      ;
  576.      move.l   (sp)+,a6                  ; restore registers
  577.      move.l   (sp)+,d0                  ; restore registers
  578. exp_end  rts                          ; return (seglist in D0!)
  579.      ;
  580.      ;      Device "ExtFunc" routine
  581.      ;
  582. dev_Null:
  583.      moveq      #0,d0                   ; set return code
  584.      bra.b      exp_end                  ; return
  585.      ;
  586.      ;
  587.      ;
  588.      IFNE      DEBUG
  589. printIO:
  590.      movem.l  d0-d7/a0-a6,-(sp)
  591.      addq.l   #1,ioctr
  592.      move.l   ioctr,-(sp)
  593.      move.l   a1,-(sp)
  594.      move.l   a0,-(sp)
  595.      pea.l      0$
  596.      pea.l      Name
  597.      DISABLE  TBE|INTF_PORTS
  598.      jsr      _SendText(pc)
  599.      ENABLE   TBE|INTF_PORTS
  600.      lea.l      20(sp),sp
  601.  
  602.      moveq      #0,d0
  603.      move.w   IO_COMMAND(a1),d0
  604.      move.l   d0,-(sp)
  605.      move.l   MN_REPLYPORT(a1),-(sp)
  606.      moveq      #0,d0
  607.      move.b   LN_TYPE(a1),d0
  608.      move.l   d0,-(sp)
  609.      pea.l      1$
  610.      pea.l      Name
  611.      DISABLE  TBE|INTF_PORTS
  612.      jsr      _SendText(pc)
  613.      ENABLE   TBE|INTF_PORTS
  614.      lea.l      20(sp),sp
  615.  
  616.      move.l   IO_LENGTH(a1),-(sp)
  617.      moveq      #0,d0
  618.      move.b   IO_ERROR(a1),d0
  619.      move.l   d0,-(sp)
  620.      move.b   IO_FLAGS(a1),d0
  621.      move.l   d0,-(sp)
  622.      pea.l      2$
  623.      pea.l      Name
  624.      DISABLE  TBE|INTF_PORTS
  625.      jsr      _SendText(pc)
  626.      ENABLE   TBE|INTF_PORTS
  627.      lea.l      20(sp),sp
  628.  
  629.      move.l   IO_EXTFLAGS(a1),-(sp)
  630.      move.l   IO_RBUFLEN(a1),-(sp)
  631.      move.l   IO_ACTUAL(a1),-(sp)
  632.      pea.l      3$
  633.      pea.l      Name
  634.      DISABLE  TBE|INTF_PORTS
  635.      jsr      _SendText(pc)
  636.      ENABLE   TBE|INTF_PORTS
  637.      lea.l      20(sp),sp
  638.  
  639.      moveq      #0,d0
  640.      move.b   IO_WRITELEN(a1),d0
  641.      move.l   d0,-(sp)
  642.      move.b   IO_READLEN(a1),d0
  643.      move.l   d0,-(sp)
  644.      move.l   IO_BAUD(a1),-(sp)
  645.      pea.l      4$
  646.      pea.l      Name
  647.      DISABLE  TBE|INTF_PORTS
  648.      jsr      _SendText(pc)
  649.      ENABLE   TBE|INTF_PORTS
  650.      lea.l      20(sp),sp
  651.  
  652.      moveq      #0,d0
  653.      move.w   IO_STATUS(a1),d0
  654.      move.l   d0,-(sp)
  655.      moveq      #0,d0
  656.      move.b   IO_SERFLAGS(a1),d0
  657.      move.l   d0,-(sp)
  658.      move.b   IO_STOPBITS(a1),d0
  659.      move.l   d0,-(sp)
  660.      pea.l      5$
  661.      pea.l      Name
  662.      DISABLE  TBE|INTF_PORTS
  663.      jsr      _SendText(pc)
  664.      ENABLE   TBE|INTF_PORTS
  665.      lea.l      20(sp),sp
  666.      movem.l  (sp)+,d0-d7/a0-a6
  667.      rts
  668. 0$     dc.b      '%ls - I/O     %8lx, Cnt = %ld',0
  669. 1$     DC.B      'Type    %8ld     ReplyPort %8lx    Command  %8ld',0
  670. 2$     DC.B      'Flags   %8lx     Error     %8ld    Length   %8ld',0
  671. 3$     DC.B      'Actual  %8ld     RBufLen   %8ld    ExtFlags %8lx',0
  672. 4$     DC.B      'Baud    %8ld     ReadLen   %8ld    WriteLen %8ld',0
  673. 5$     DC.B      'StopBit %8ld     SerFlags  %8lx    Status   %8lx',0
  674.      ;
  675.      ;
  676.      ;
  677. abortIOs dc.b      'Abort Start',0
  678. abortIOe dc.b      'Abort End',0
  679. abortIOa dc.b      'Aborting',0
  680. beginIOs dc.b      'Begin Start',0
  681. beginIOe dc.b      'Begin End',0
  682. openIO     dc.b      'Open IO',0
  683. replyIO  dc.b      'replyIO',0
  684.      ds.l      0
  685. ioctr     dc.l      0
  686.      ENDC
  687.      ;
  688. cmdTable dc.w      cmd_Invalid-cmdTable              ; CMD_INVALID
  689.      dc.w      cmd_Reset-cmdTable              ; CMD_RESET
  690.      dc.w      cmd_Read-cmdTable              ; CMD_READ
  691.      dc.w      cmd_Write-cmdTable              ; CMD_WRITE
  692.      dc.w      cmd_Invalid-cmdTable              ; CMD_UPDATE
  693.      dc.w      cmd_Clear-cmdTable              ; CMD_CLEAR
  694.      dc.w      cmd_Invalid-cmdTable              ; CMD_STOP
  695.      dc.w      cmd_Invalid-cmdTable              ; CMD_START
  696.      dc.w      cmd_Flush-cmdTable              ; CMD_FLUSH
  697.      dc.w      sdcmd_Query-cmdTable              ; SDCMD_QUERY
  698.      dc.w      sdcmd_Break-cmdTable              ; SDCMD_BREAK
  699. endTable dc.w      sdcmd_SetParams-cmdTable          ; SDCMD_SETPARAMS
  700.      ;
  701.      ;      Device BeginIO routine
  702.      ;
  703. dev_BeginIO:
  704.      move.l   a5,-(sp)                  ; save register
  705.      movea.l  a6,a5                   ; save base
  706.      movea.l  SysBase(pc),a6              ; get ExecBase
  707.      DEBUGIO  beginIOs
  708.      ;
  709.      move.b   #NT_MESSAGE,LN_TYPE(a1)          ; set type
  710.      clr.b      IO_ERROR(a1)                  ; clear error
  711.      ;
  712.      andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),IO_FLAGS(a1) ; clear flags
  713.      ;
  714.      move.w   IO_COMMAND(a1),d0              ; get command
  715.      add.w      d0,d0                   ; multiply by 2
  716.      cmpi.w   #endTable-cmdTable,d0           ; in range?
  717.      bhi.b      30$                      ; nope, error
  718.      ;
  719.      move.w   cmdTable(pc,d0.w),d0              ; get routine offset
  720.      jsr      cmdTable(pc,d0.w)              ; go do it
  721.      tst.l      d0                      ; I/O completed?
  722.      bne.b      19$                      ; nope, go return
  723.      ;
  724. 10$     DEBUGIO  beginIOe
  725.      btst      #IOB_QUICK,IO_FLAGS(a1)          ; need to reply?
  726.      bne.b      20$                      ; nope, branch
  727. 15$     jsr      _LVOReplyMsg(a6)              ; send it back
  728.      ;
  729. 19$     andi.b   #~(1<<IOB_QUICK),IO_FLAGS(a1)         ; clear quick bit
  730. 20$     movea.l  a5,a6                   ; restore base
  731.      movea.l  (sp)+,a5                  ; restore register
  732.      rts                          ; return
  733.      ;
  734. 30$     move.b   #IOERR_NOCMD,IO_ERROR(a1)          ; invalid command
  735.      bra.b      10$                      ; branch
  736.      ;
  737.      ;      Device AbortIO routine
  738.      ;
  739. dev_AbortIO:
  740.      move.l   a5,-(sp)                  ; save registers
  741.      movea.l  a6,a5                   ; save base
  742.      movea.l  SysBase(pc),a6              ; get ExecBase
  743.      DEBUGIO  abortIOs
  744.      ;
  745.      DISABLE                      ; disable interrupts
  746.      ;
  747.      move.b   IO_FLAGS(a1),d1
  748.      btst      #IOSERB_QUEUED,d1              ; queued request?
  749.      bne.b      40$                      ; yep, branch
  750.      ;
  751.      btst      #1<<IOSERB_ACTIVE,d1              ; active request?
  752.      bne.b      10$                      ; nope, just exit
  753.      ;
  754.      move.w   IO_COMMAND(a1),d0              ; get command
  755.      subq.w   #CMD_READ,d0                  ; was it a read?
  756.      beq.b      20$                      ; yep, go process
  757.      ;
  758.      subq.w   #CMD_WRITE-CMD_READ,d0          ; was it a write?
  759.      beq.b      30$                      ; yep, go process
  760.      ;
  761.      subq.w   #SDCMD_BREAK-CMD_WRITE,d0          ; was it a break?
  762.      beq.b      30$                      ; yep, go process
  763.      ;
  764.      ;      Fall through or enter from below
  765.      ;
  766. 10$     ENABLE                       ; enable ints and return
  767. 15$     movea.l  a5,a6                   ; restore base
  768.      movea.l  (sp)+,a5                  ; restore registers
  769.      rts                          ; return
  770.      ;
  771.      ;      Abort an active read request
  772.      ;
  773. 20$     clr.l      cr_IOReq                  ; no longer active
  774.      bra.b      50$                      ; go set flags
  775.      ;
  776.      ;      Abort an active write request
  777.      ;
  778. 30$     clr.l      cw_Length                  ; no longer active
  779.      clr.l      cw_IOReq                  ; no longer active
  780.      move.l   cw_Buffer(pc),d0              ; get buffer ptr
  781.      sub.l      IO_DATA(a1),d0              ; calc number of bytes xfer'd
  782.      move.l   d0,IO_ACTUAL(a1)              ; store
  783.      ;
  784.      ;      Force a TBE interrupt to get the next write going.
  785.      ;
  786.      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  787.      bra.b      50$                      ; go set flags
  788.      ;
  789.      ;      Remove I/O from queue.
  790.      ;
  791. 40$     move.l   a1,-(sp)                  ; save ptr
  792.      ; This is the REMOVE macro
  793.      move.l   (a1)+,a0
  794.      move.l   (a1),a1                  ; LN+PRED
  795.      move.l   a0,(a1)
  796.      move.l   a1,LN_PRED(a0)
  797.      ;
  798.      movea.l  (sp)+,a1                  ; restore ptr
  799.      ;
  800.      ;      Set error and return I/O
  801.      ;
  802. 50$     move.b   #IOERR_ABORTED,IO_ERROR(a1)          ; set error code
  803.      move.b   IO_FLAGS(a1),d1              ; get flags
  804.      ori.b      #1<<IOSERB_ABORT,d1              ; set abort flag
  805.      andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),d1  ; clear flags
  806.      move.b   d1,IO_FLAGS(a1)              ; store flags
  807.      DEBUGIO  abortIOe
  808.      btst      #1<<IOB_QUICK,d1              ; need to reply?
  809.      bne.b      10$                      ; nope, branch
  810.      jsr      _LVOReplyMsg(a6)              ; send it back
  811.      bra.b      10$                      ; branch to return
  812.      ;
  813.      ;      Abort all active/queued commands and reset internal state
  814.      ;
  815. cmd_Reset:
  816.      move.l   a1,-(sp)                  ; save I/O request
  817.      bsr.b      cmd_Flush                  ; go abort queued requests
  818.      ;
  819.      DISABLE                      ; disable interrupts
  820.      ;
  821.      ;      This must follow the DISABLE
  822.      ;
  823.      exg      a5,a6                   ; exchange base and ExecBase
  824.      ;
  825.     IFNE NEWCODE
  826.      move.l   cr_IOReq(pc),a1              ; active read?
  827.      beq.b      10$                      ; nope, branch
  828.     ELSE
  829.      move.l   cr_IOReq(pc),d0              ; active read?
  830.      beq.b      10$                      ; nope, branch
  831.      movea.l  d0,a1                   ; get I/O request
  832.     ENDC
  833.      bsr      dev_AbortIO                  ; go abort it
  834.      ;
  835.      ;
  836.      ;
  837.     IFNE NEWCODE
  838. 10$     move.l   cw_IOReq(pc),a1              ; active write?
  839.      beq.b      20$                      ; nope, branch
  840.     ELSE
  841. 10$     move.l   cw_IOReq(pc),d0              ; active write?
  842.      beq.b      20$                      ; nope, branch
  843.      movea.l  d0,a1                   ; get I/O request
  844.     ENDC
  845.      bsr      dev_AbortIO                  ; go abort it
  846.      ;
  847. 20$     exg      a5,a6                   ; restore base and ExecBase
  848.      movea.l  (sp)+,a1                  ; restore I/O request
  849.      moveq      #8,d0                   ; get char size
  850.      move.b   d0,IO_READLEN(a1)              ; set read length
  851.      move.b   d0,IO_WRITELEN(a1)              ; set write length
  852.      moveq      #1,d0                   ; get stop bits
  853.      move.b   d0,IO_STOPBITS(a1)              ; set stop bits
  854.      move.l   vb_DefBaud(a5),IO_BAUD(a1)          ; set to default baud
  855.      move.l   vb_DefRBufLen(a5),IO_RBUFLEN(a1)    ; set to default buflen
  856.      bsr      internalReset               ; go set/verify parameters
  857.      move.b   d0,IO_ERROR(a1)              ; set error code
  858.      ENABLE                       ; enable interrupts
  859.      ;
  860.      ;      Set RC and return
  861.      ;
  862.      moveq      #0,d0                   ; I/O complete
  863.      rts                          ; return
  864.      ;
  865.      ;      Abort all "queued" requests, leaving all active alone.
  866.      ;
  867. cmd_Flush:
  868.      movem.l  a1/a2,-(sp)                  ; save registers
  869.      DISABLE                      ; disable interrupts
  870.      ;
  871.      ;      Abort all queued read requests.
  872.      ;
  873.      lea.l      readQ(pc),a2                  ; get ptr to read queue
  874.      bsr.b      20$                      ; branch to abort
  875.      ;
  876.      ;      Abort all queued write requests.
  877.      ;
  878.      lea.l      writeQ(pc),a2               ; get ptr to write queue
  879.      bsr.b      20$                      ; branch to abort
  880.      ;
  881.      ;      Enable, restore, and return to caller
  882.      ;
  883.      ENABLE                       ; enable interrupts
  884.      movem.l  (sp)+,a1/a2                  ; restore registers
  885.      ;
  886.      ;      Set RC and return
  887.      ;
  888.      moveq      #0,d0                   ; I/O complete
  889.      ;
  890.      ;      !!!NOTE!!!  In a mad attempt to save 2 bytes, this RTS is used
  891.      ;      by the subroutine below.  Why waste 'em?  B-)
  892.      ;
  893. 10$     rts                          ; return ( used below too!! )
  894.      ;
  895.      ;      Subroutine to remove and reply each I/O request.
  896.      ;
  897. 20$     movea.l  a2,a0                   ; get list ptr
  898.      ; This is the REMHEAD macro
  899. 25$     move.l    (a0),a1
  900.      move.l    (a1),d0
  901.      beq.b       25$
  902.      move.l    d0,(a0)
  903.      exg.l       d0,a1
  904.      move.l    a0,LN_PRED(a1)
  905.      ;
  906.      tst.l      d0                      ; end of list?
  907.      beq.b      10$                      ; yep, branch to return
  908.      ;
  909.      movea.l  d0,a1                   ; get I/O request
  910.      andi.b   #~(1<<IOSERB_QUEUED),IO_FLAGS(a1)   ; no longer queued
  911.      moveq      #IOERR_ABORTED,d0              ; indicate aborted
  912.      move.b   d0,IO_ERROR(a1)              ; store status
  913.      ;
  914.      jsr      _LVOReplyMsg(a6)              ; send it back
  915.      bra.b      20$                      ; continue with next
  916.      ;
  917.      ;      Process a CMD_READ request.
  918.      ;
  919. cmd_Read:
  920.      ;
  921.      ;      Zero length requests just get returned.
  922.      ;
  923.      clr.l      IO_ACTUAL(a1)               ; clear bytes read
  924.      move.l   IO_LENGTH(a1),d0              ; get length and test
  925.      beq.b      20$                      ; yep, leave
  926.      ;
  927.      ;      This can be used to circumvent a bug in NComm 3.0 which
  928.      ;      references the buffer even when there was nothing read.
  929.      ;
  930.     IFNE     NCOMM
  931.      move.l   IO_DATA(A1),a0              ; get data pointer
  932.      clr.b      (a0)                      ; clear first byte in buffer
  933.     ENDC
  934.      ;
  935.      ;      The disable counter works just like exec's TDNestCnt field.  It's
  936.      ;      initialized to -1.  After incrementing, if it is 0, then we
  937.      ;      can attempt to process this request immediately.  If it's > 0,
  938.      ;      then we're already disabled and we must queue this request.
  939.      ;
  940.      addq.b   #1,disableRead              ; incr disable count
  941.      bgt.b      50$                      ; >0, already disabled
  942.      ;
  943.      ;      If we're already processing an request, this one has to wait
  944.      ;      until that one is done, so go queue it.
  945.      ;
  946.      move.l   cr_IOReq(pc),d1              ; have an active request?
  947.      bne.b      50$                      ; yep, go queue this one
  948.      ;
  949.      ;      If we don't have enough bytes to satisfy this request then go
  950.      ;      queue it.
  951.      ;
  952.      cmp.l      i_InCnt(pc),d0              ; length > current bytes?
  953.      bgt.b      50$                      ; yep, go queue it
  954.      ;
  955.      ;      Setup fields and go copy the data
  956.      ;
  957.      move.l   IO_DATA(a1),cr_OutPtr           ; get/set output ptr
  958.      move.l   IO_LENGTH(a1),cr_Length          ; get/set output count
  959.      bsr      copyData                  ; go copy 'em
  960.      moveq      #0,d0                   ; I/O complete
  961.      ;
  962.      ;      We're done, so back off the disable counter.
  963.      ;
  964. 10$     subq.b   #1,disableRead              ; decr disable count
  965.      ;
  966.      ;      Return to caller
  967.      ;
  968. 20$     rts                          ; return
  969.      ;
  970.      ;      Just set flags and queue.  The read interrupt will handle it.
  971.      ;
  972. 50$     ori.b      #1<<IOSERB_QUEUED,IO_FLAGS(a1)      ; indicate queued
  973.      ;
  974.      ;      Add this request to the end.
  975.      ;
  976.      DISABLE                      ; disable interrupts
  977.      lea.l      readQ(pc),a0                  ; get pointer to read queue
  978.      ; This is the ADDTAIL macro
  979.      addq.l   #LH_TAIL,a0
  980.      move.l   LN_PRED(a0),d0
  981.      move.l   a1,LN_PRED(a0)
  982.      exg      d0,a0
  983.      movem.l  d0/a0,(a1)
  984.      move.l   a1,(a0)
  985.      ;
  986.      ENABLE                       ; enable interrupts
  987.      ;
  988.      ;      Indicate that this request was not handled immediatly.
  989.      ;
  990.      moveq      #1,d0                   ; I/O not complete
  991.      bra.b      10$                      ; branch to return
  992.      ;
  993.      ;      Process a CMD_WRITE request.
  994.      ;
  995. cmd_Write:
  996.      clr.l      IO_ACTUAL(a1)               ; clear bytes written
  997.      tst.l      IO_LENGTH(a1)               ; get length and test
  998.      beq.b      wbexit                  ; yep, leave
  999.      ;
  1000.      ;      Entry point for Break command and fall through from cmd_Write.
  1001.      ;
  1002. sdcmd_Break:
  1003.      ;
  1004.      ;      Just set flags and queue. The TBE interrupt will handle it.
  1005.      ;
  1006.      ori.b      #1<<IOSERB_QUEUED,IO_FLAGS(a1)      ; indicate queued
  1007.      ;
  1008.      ;      Protect.
  1009.      ;
  1010.      DISABLE                      ; disable interrupts
  1011.      ;
  1012.      ;      Add request to end of queue.
  1013.      ;
  1014.      lea.l      writeQ(pc),a0               ; get queue list ptr
  1015.      ; This is the ADDTAIL macro
  1016.      addq.l   #LH_TAIL,a0
  1017.      move.l   LN_PRED(a0),d0
  1018.      move.l   a1,LN_PRED(a0)
  1019.      exg      d0,a0
  1020.      movem.l  d0/a0,(a1)
  1021.      move.l   a1,(a0)
  1022.      ;
  1023.      ;      If we have an active request, don't force interrupt.
  1024.      ;
  1025.      move.l   cw_IOReq(pc),d0              ; have an active request?
  1026.      bne.b      10$                      ; yep, branch
  1027.      ;
  1028.      ;      Force a TBE interrupt to get the writes going.
  1029.      ;
  1030.      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  1031.      ;
  1032.      ;      Enable, set RC and return to caller.
  1033.      ;
  1034. 10$     ENABLE                       ; enable interrupts
  1035.      moveq      #1,d0                   ; I/O not complete
  1036. wbexit     rts                          ; return
  1037.      ;
  1038.      ;      Resets serial read buffer
  1039.      ;
  1040.      ;      Since this routine is called internally, it must NOT reference
  1041.      ;      the I/O request.
  1042.      ;
  1043. cmd_Clear:
  1044.      DISABLE                      ; disable interrupts
  1045.      ;
  1046.      ;      Load registers
  1047.      ;
  1048.      move.l   vb_CurRBuf(a5),d0              ; get internal buffer ptr
  1049.      move.l   vb_CurRBufLen(a5),d1              ; and internal buffer len
  1050.      lea.l      i_BufPtr(pc),a0              ; get ptr internal control
  1051.      ;
  1052.      ;      Initialize global buffer variables
  1053.      ;
  1054.      move.l   d0,(a0)                  ; store buffer ptr
  1055.      move.l   d0,4(a0)                  ; set current input ptr
  1056.      move.l   d0,8(a0)                  ; set current output ptr
  1057.      add.l      d1,d0                   ; add buffer length
  1058.      move.l   d0,12(a0)                  ; store ptr to end of buffer
  1059.      clr.l      16(a0)                  ; clear byte cnt
  1060.      move.l   vb_CurBaud(a5),d0              ; get internal baud
  1061.      lsr.l      #4,d0                   ; divide by 16
  1062.      sub.l      d0,d1                   ; subtract from length
  1063.      move.l   d1,20(a0)                  ; set threshold
  1064.      ;
  1065.      ;      Enable, set RC and return.
  1066.      ;
  1067.      ENABLE                       ; enable interrupts
  1068.      moveq      #0,d0                   ; I/O complete
  1069.      rts                          ; return
  1070.      ;
  1071.      ;
  1072.      ;
  1073. cmd_Invalid
  1074.      move.b   #IOERR_NOCMD,IO_ERROR(a1)          ; set bad status
  1075.      moveq      #0,d0                   ; I/O complete
  1076.      rts                          ; return
  1077.      ;
  1078.      ;      Returns number of bytes currently in internal buffer and
  1079.      ;      current serial port status.
  1080.      ;
  1081.      ;      NOTE:  Not completely compatible with standard serial.device
  1082.      ;      since it doesn't return the upper byte of IO_STATUS.
  1083.      ;
  1084. sdcmd_Query:
  1085.      DISABLE                      ; disable interrupts
  1086.      moveq      #0,d0                   ; clear d0
  1087.      move.b   _ciabpra,d0                  ; get PR register
  1088.      andi.b   #~PRTMASK,d0                  ; zap printer bits
  1089.      ;
  1090.      ;      Uncomment the following to turn on the DSR bit.  This was done
  1091.      ;      for a user whose DSR pin did not function.
  1092.      ;
  1093.     IFNE SETDSR
  1094.      andi.b   #~(1<<CIAB_COMDSR),d0             ; set DSR
  1095.     ENDC
  1096.      ;
  1097.      ;
  1098.      ;
  1099.      move.w   d0,IO_STATUS(a1)              ; store status
  1100.      move.l   i_InCnt(pc),IO_ACTUAL(a1)          ; byte left in buffer
  1101.      ;
  1102.      ;      Enable, set RC and return.
  1103.      ;
  1104.      ENABLE                       ; enable interrupts
  1105.      moveq      #0,d0                   ; I/O complete
  1106.      rts                          ; return
  1107.      ;
  1108.      ;
  1109.      ;
  1110. sdcmd_SetParams:
  1111.      ;
  1112.      ;      Validate the read, write, and stop bit lengths.
  1113.      ;
  1114.      moveq      #8,d0                   ; get char length
  1115.      cmp.b      IO_READLEN(a1),d0              ; 8 bit chars for read?
  1116.      bne.b      40$                      ; nope, branch
  1117.      cmp.b      IO_WRITELEN(a1),d0              ; 8 bit chars for write?
  1118.      bne.b      40$                      ; nope, branch
  1119.      moveq      #1,d0                   ; get stop bits
  1120.      cmp.b      IO_STOPBITS(a1),d0              ; 1 stop bit?
  1121.      bne.b      40$                      ; nope, branch
  1122.      ;
  1123.      ;      Get and validate the baud rate.
  1124.      ;
  1125.      move.l   IO_BAUD(a1),d1              ; get baud from I/O req
  1126.      bne.b      20$                      ; specified?
  1127.      move.l   vb_CurBaud(a5),d1              ; get current baud from base
  1128.      bne.b      20$                      ; specified?
  1129.      move.l   vb_DefBaud(a5),d1              ; get default baud from base
  1130. 20$     cmpi.l   #110,d1                  ; too low?
  1131.      blt.b      40$                      ; error
  1132.      cmpi.l   #292000,d1                  ; too high?
  1133.      bgt.b      40$                      ; error
  1134.      ;
  1135.      ;      Get and validate the buffer length.
  1136.      ;
  1137.      move.l   IO_RBUFLEN(a1),d0              ; get buffer length
  1138.      bne.b      30$                      ; specified?
  1139.      move.l   vb_CurRBufLen(a5),d0              ; get current from base
  1140.      bne.b      30$                      ; specified?
  1141.      move.l   vb_DefRBufLen(a5),d0              ; get default from base
  1142.      ;
  1143. 30$     bsr.b      internalReset               ; go init baud and buffer
  1144. 35$     move.b   d0,IO_ERROR(a1)              ; set error code
  1145.      bne.b      39$
  1146.      ;
  1147.      ;      If the 7wire bit is not on, we will only use 3-wire protocol
  1148.      ;
  1149.      moveq      #0,d0                   ; clear flag
  1150.      btst      #SERB_7WIRE,IO_SERFLAGS(a1)          ; use 7wire handshaking?
  1151.      beq.b      36$                      ; nope, branch
  1152.      moveq      #1,d0                   ; set flag
  1153. 36$     move.b   d0,Handshake                  ; store flag
  1154.      ;
  1155.      ;      Set RC and return.
  1156.      ;
  1157. 39$     moveq      #0,d0                   ; I/O complete
  1158.      rts                          ; return
  1159.      ;
  1160.      ;      Invalid parm detected.
  1161.      ;
  1162. 40$     moveq      #SerErr_InvParam,d0              ; set error
  1163.      bra.b      35$                      ; go return
  1164.      ;
  1165.      ;      Reset the buffer and baud rate
  1166.      ;
  1167.      ;      Registers:  D0 = Buffer length
  1168.      ;              D1 = Baud rate
  1169.      ;
  1170. internalReset:
  1171.      ;
  1172.      ;      Disable interrupts.
  1173.      ;
  1174.      DISABLE                      ; disable interrupts
  1175.      ;
  1176.      ;      Save buffer length and go set serper.
  1177.      ;
  1178.      move.l   d0,-(sp)                  ; save D0
  1179.      move.l   d1,d0                   ; get baud rate
  1180.      bsr.b      setPeriod                  ; go set the serper register
  1181.      move.l   (sp)+,d0                  ; restore D0
  1182.      ;
  1183.      ;      Determine if the buffer length is adequate for the selected CPS.
  1184.      ;      If not, use 64K for the length.
  1185.      ;
  1186.      move.l   vb_CurBaud(a5),d1              ; get current baud
  1187.      lsr.l      #$3,d1                  ; divide by 8
  1188.      cmp.l      d1,d0                   ; buflen > CPS
  1189.      bhi.b      10$                      ; yep, branch
  1190.      move.l   #65536,d0                  ; else use 64K
  1191.      ;
  1192. 10$     bsr.b      allocBuf                  ; go allocate a new buffer
  1193.      ;
  1194.      ;      Enable and return to caller.
  1195.      ;
  1196.      ENABLE                       ; enable interrupts
  1197.      rts                          ; return (D0 has status)
  1198.      ;
  1199.      ;      Set serial period register
  1200.      ;
  1201. setPeriod:
  1202.      cmp.l      vb_CurBaud(a5),d0              ; current baud = new baud?
  1203.      beq.b      40$                      ; yep, just exit
  1204.      move.l   d0,vb_CurBaud(a5)              ; save new baud
  1205.      move.l   d0,d1                   ; save again
  1206.      lsl.l      #3,d0                   ; baud *= 8
  1207.      sub.l      d1,d0                   ; baud -= saved baud
  1208.      move.l   #25000000,d1                  ; get NTSC base
  1209.      cmpi.b   #50,PowerSupplyFrequency(a6)          ; PAL machine?
  1210.      bne.b      10$                      ; nope, branch
  1211.      move.l   #24772416,d1                  ; get PAL base
  1212. 10$     cmpi.l   #$FFFF,d0                  ; Divide
  1213.      ble.b      20$                      ;
  1214.      lsr.l      #5,d0                   ;
  1215.      divu.w   d0,d1                   ;
  1216.      andi.l   #$FFFF,d1                  ;
  1217.      lsr.l      #5,d1                   ;
  1218.      bra.b      30$                      ;
  1219. 20$     divu.w   d0,d1                   ;
  1220. 30$     move.w   d1,_serper                  ; set period value
  1221. 40$     rts
  1222.      ;
  1223.      ;      Allocate new internal buffer
  1224.      ;
  1225. allocBuf:
  1226.      cmp.l      vb_CurRBufLen(a5),d0              ; len same as previous?
  1227.      beq.b      10$                      ; yep, so no need to alloc
  1228.      move.l   d0,d1                   ; save length
  1229.      movem.l  d1/a1,-(sp)                  ; save registers
  1230.      moveq      #MEMF_PUBLIC,d1              ; public memory
  1231.      jsr      _LVOAllocMem(a6)              ; go allocate it
  1232.      movem.l  (sp)+,d1/a1                  ; restore registers
  1233.      tst.l      d0                      ; did we get it?
  1234.      beq.b      20$                      ; if zero, error
  1235.      bsr.b      freeBuf                  ; go free previous buffer
  1236.      move.l   d0,vb_CurRBuf(a5)              ; store new ptr
  1237.      move.l   d1,vb_CurRBufLen(a5)              ; and length
  1238.      bsr      cmd_Clear                  ; go setup buffer
  1239. 10$     moveq      #0,d0                   ; success
  1240. 15$     rts                          ; return
  1241. 20$     moveq      #SerErr_BufErr,d0              ; set error status
  1242.      bra.b      15$                      ; return
  1243.      ;
  1244.      ;      Free internal buffer
  1245.      ;
  1246. freeBuf:
  1247.      movem.l  d0-d1/a0-a1,-(sp)              ; save registers
  1248.      move.l   vb_CurRBuf(a5),d0              ; is one there?
  1249.      beq.b      10$                      ; no so branch
  1250.      movea.l  d0,a1                   ; get ptr
  1251.      move.l   vb_CurRBufLen(a5),d0              ; get length
  1252.      clr.l      vb_CurRBuf(a5)              ; clear
  1253.      clr.l      vb_CurRBufLen(a5)              ; clear
  1254.      jsr      _LVOFreeMem(a6)              ; free it
  1255. 10$     movem.l  (sp)+,d0-d1/a0-a1              ; restore registers
  1256.      rts                          ; return
  1257.      ;
  1258.      ;      Checks CTS status and if clear generates a TBE interrupt or
  1259.      ;      requeues the timer request.
  1260.      ;
  1261.      ;      Entered from Exec using the MsgPort callback.
  1262.      ;
  1263.      ;      Input:   a6 = ExecBase
  1264.      ;      Output:  none
  1265.      ;
  1266.      ;      No need to preserve d0/d1/a0/a1
  1267.      ;
  1268. timerRtn:
  1269.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1270.      ; This is the REMOVE macro
  1271.      move.l   (a1)+,a0
  1272.      move.l   (a1),a1                  ; LN+PRED
  1273.      move.l   a0,(a1)
  1274.      move.l   a1,LN_PRED(a0)
  1275.      ;
  1276.      ;      If we were breaking, reset adkcon.
  1277.      ;
  1278.      lea      _custom,a0                  ; get ptr to custom regs
  1279.      btst      #ADKB_UARTBRK-8,adkconr(a0)          ; were we breaking?
  1280.      beq.b      10$                      ; nope, skip reset
  1281.      ;
  1282.      move.w   #ADKF_UARTBRK,adkcon(a0)          ; stop breaking
  1283.      ;
  1284.      ;
  1285.      ;
  1286. 10$     move.b   Handshake(pc),d0              ; are we handshaking?
  1287.      beq.b      20$                      ; nope, generate interrupt
  1288.      btst      #CIAB_COMCTS,_ciabpra           ; clear to send?
  1289.      beq.b      20$                      ; yep, go start writing
  1290.      ;
  1291.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1292.      move.l   #1000,IOTV_TIME+TV_MICRO(a1)          ; wait for .001 seconds
  1293.      jsr      _LVOSendIO(a6)              ; go queue it
  1294.      bra.b      30$                      ; branch to return
  1295.      ;
  1296.      ;      CTS is clear so generate TBE interrupt to restart writing
  1297.      ;
  1298. 20$     move.w   #INTF_SETCLR|INTF_TBE,intreq(a0)    ; set TBE interrupt
  1299. 30$     rts                          ; return
  1300.      ;
  1301.      ;      Non serial interrupt
  1302.      ;
  1303. level1n:
  1304.      movem.l  d0-d1/a0-a1/a5-a6,-(sp)          ; save registers
  1305.      lea      _custom,a0                  ; get ptr to custom regs
  1306.      move.w   intenar(a0),d1              ; get enabled interrupts
  1307.      and.w      intreqr(a0),d1              ; and in requested interrupts
  1308.      movea.l  SysBase(pc),a6              ; get ExecBase
  1309.      ;
  1310.      btst      #INTB_DSKBLK,d1              ; Disk block done?
  1311.      beq.b      10$                      ; nope, branch
  1312.      ;
  1313.      movem.l  IVDSKBLK(a6),a1/a5              ; get data and code ptrs
  1314.      pea.l      20$(pc)                  ; push return address
  1315.      jmp      (a5)                      ; jump to routine
  1316.      ;
  1317. 10$     btst      #INTB_SOFTINT,d1              ; software interrupt?
  1318.      beq.b      20$                      ; nope, branch
  1319.      ;
  1320.      movem.l  IVSOFTINT(a6),a1/a5              ; get data and code ptrs
  1321.      pea.l      20$(pc)                  ; push return address
  1322.      jmp      (a5)                      ; jump to routine
  1323.      ;
  1324. 20$     movem.l  (sp)+,d0-d1/a0-a1/a5-a6          ; restore registers
  1325.      rte                          ; return
  1326.      ;
  1327.      ;      Level 1 interrupt handler
  1328.      ;
  1329. level1:
  1330.      btst      #INTB_INTEN-8,_intenar          ; interrupts enabled?
  1331.      beq.b      35$                      ; nope, ignore
  1332.      btst      #INTB_SOFTINT,_intreqr+1          ; software interrupt?
  1333.      bne.b      level1n                  ; nope, branch
  1334.      btst      #INTB_TBE,_intreqr+1              ; xmit buffer empty?
  1335.      beq.b      level1n                  ; nope, invoke old handler
  1336.      ;
  1337.      ;      Handle "Transmit Buffer Empty" interrupt (write)
  1338.      ;
  1339.      move.w   #INTF_TBE,_intreq              ; clear interrupt
  1340.      move.l   d0,-(sp)                  ; save D0 (faster than MOVEM)
  1341.      move.l   a0,-(sp)                  ; save A0 (faster than MOVEM)
  1342.      ;
  1343.      ;      If we're not handshaking, bypass it.
  1344.      ;
  1345. 10$     move.b   Handshake(pc),d0              ; are we handshaking?
  1346.      beq.b      20$                      ; nope, skip CTS test
  1347.      btst      #CIAB_COMCTS,_ciabpra           ; clear to send?
  1348.      bne.b      40$                      ; nope, branch
  1349.      ;
  1350.      ;      If cw_Length goes negative here, we are either done with a
  1351.      ;      request or we were called as a result of a fake interrupt
  1352.      ;      to force us to get the next request going.
  1353.      ;
  1354. 20$     subq.l   #1,cw_Length                  ; decr write length
  1355.      blt.b      60$                      ; < zero, done, branch
  1356.      ;
  1357.      ;      Currently processing a request.
  1358.      ;
  1359.      movea.l  cw_Buffer(pc),a0              ; get buffer ptr
  1360.      move.w   #256,d0                  ; set stop bit
  1361.      move.b   (a0)+,d0                  ; get next byte
  1362.      move.l   a0,cw_Buffer                  ; store buffer ptr
  1363.      move.w   d0,_serdat                  ; store in serdat reg
  1364.      ;
  1365. 30$     movea.l  (sp)+,a0                  ; restore registers
  1366.      move.l   (sp)+,d0                  ; restore registers
  1367. 35$     rte                          ; return
  1368.      ;
  1369.      ;      Queue a timer request to recheck CTS status
  1370.      ;
  1371. 40$     movem.l  d1/a1/a6,-(sp)              ; save registers
  1372.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1373.      move.l   #1000,IOTV_TIME+TV_MICRO(a1)          ; wait for .001 seconds
  1374.      movea.l  SysBase(pc),a6              ; get ExecBase
  1375.      jsr      _LVOSendIO(a6)              ; queue the request
  1376.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1377.      bra.b      30$                      ; go return
  1378.      ;
  1379.      ;      There aren't anymore requests, so clear and exit
  1380.      ;
  1381. 50$     clr.l      cw_Length-Start(a6)              ; clear length
  1382.      clr.l      cw_IOReq-Start(a6)              ; clear
  1383.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1384.      bra.b      30$                      ; go return
  1385.      ;
  1386.      ;      Write request completed
  1387.      ;
  1388. 60$     movem.l  d1/a1/a6,-(sp)              ; save registers
  1389.      ;
  1390.      move.l   cw_IOReq(pc),d0              ; active I/O request?
  1391.      beq.b      70$                      ; nope, branch
  1392.      ;
  1393.      ;      Reply it and setup for next
  1394.      ;
  1395.      movea.l  d0,a1                   ; get I/O request
  1396.      andi.b   #~(1<<IOSERB_ACTIVE),IO_FLAGS(a1)   ; no longer active
  1397.      clr.b      IO_ERROR(a1)                  ; no error
  1398.      movea.l  SysBase(pc),a6              ; get ExecBase
  1399.      DEBUGIO  replyIO
  1400.      jsr      _LVOReplyMsg(a6)              ; return I/O request
  1401.      ;
  1402. 70$     lea.l      Start(pc),a6                  ; get section base
  1403.      ;
  1404.      lea.l      writeQ(pc),a1               ; get ptr to write queue
  1405.      move.l   (a1),a0                  ; get head of list
  1406.      move.l   (a0),d0                  ; get successor
  1407.      beq.b      50$                      ; end of list? yep, branch
  1408.      ;
  1409.      ;      Remove the node from the list
  1410.      ;
  1411.      move.l   d0,(a1)                  ; make new head
  1412.      exg.l      d0,a0                   ; swap nodes
  1413.      move.l   a1,LN_PRED(a0)              ; store predecessor
  1414.      ;
  1415.      move.l   d0,a1                   ; get I/O request
  1416.      ;
  1417.      ;      If it's a BREAK, then branch to process as such.
  1418.      ;
  1419.      cmpi.w   #SDCMD_BREAK,IO_COMMAND(a1)          ; BREAK command?
  1420.      beq.b      100$                      ; yep, branch
  1421.      ;
  1422.      ;      Check for absolute length
  1423.      ;
  1424.      move.l   IO_DATA(a1),a0              ; get data ptr
  1425.      moveq      #-1,d1                  ; get value
  1426.      move.l   IO_LENGTH(a1),d0              ; get length
  1427.      cmp.l      d1,d0                   ; length = -1?
  1428.      bne.b      90$                      ; nope, skip scan
  1429.      ;
  1430.      ;      Scan the data for null to calc the length
  1431.      ;
  1432.      move.l   a0,d1                   ; save data ptr
  1433.     ; Buffer size is multiple of 64bytes so we can safely move a long
  1434. 80$     move.l   (a0),d0                  ; move a long into d0
  1435.      addq.l   #1,a0                   ; update pointer
  1436.      tst.b      d0                      ; does it equal 0? (first byte)
  1437.      beq.b      81$                      ; yep, finish
  1438.      addq.l   #1,a0                   ; update pointer
  1439.      lsr.l      #8,d0                   ; shift too second byte
  1440.      tst.b      d0                      ; does it equal 0? (second byte)
  1441.      beq.b      81$                      ; yep, finish
  1442.      addq.l   #1,a0                   ; update pointer
  1443.      lsr.l      #8,d0                   ; shift too third byte
  1444.      tst.b      d0                      ; does it equal 0? (third byte)
  1445.      beq.b      81$                      ; yep, finish
  1446.      addq.l   #1,a0                   ; update pointer
  1447.      lsr.l      #8,d0                   ; shift too fourth byte
  1448.      tst.b      d0                      ; does it equal 0? (fourth byte)
  1449.      beq.b      81$                      ; yep, finish
  1450.      bra.b      80$                      ; loop
  1451. 81$
  1452.      suba.l   d1,a0                   ; calc # of bytes
  1453.      move.l   a0,d0                   ; xfer
  1454.      movea.l  d1,a0                   ; get data ptr
  1455.      ;
  1456. 90$     move.l   d0,IO_ACTUAL(a1)              ; go ahead and set it
  1457.      move.b   IO_FLAGS(a1),d1
  1458.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1459.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1460.      move.b   d1,IO_FLAGS(a1)
  1461.      move.l   d0,cw_Length-Start(a6)          ; store length
  1462.      move.l   a0,cw_Buffer-Start(a6)          ; store buffer ptr
  1463.      move.l   a1,cw_IOReq-Start(a6)           ; store I/O request ptr
  1464.      ;
  1465.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1466.      bra      10$                      ; go start request
  1467.      ;
  1468.      ;      Start the BREAK.
  1469.      ;
  1470. 100$     move.b   IO_FLAGS(a1),d1
  1471.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1472.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1473.      move.b   d1,IO_FLAGS(a1)
  1474.      clr.l      cw_Length-Start(a6)              ; clear length
  1475.      move.l   a1,cw_IOReq-Start(a6)           ; store I/O request ptr
  1476.      move.w   #ADKF_SETCLR|ADKF_UARTBRK,_adkcon   ; start break
  1477.      move.l   IO_BRKTIME(a1),d0              ; get break time
  1478.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1479.      move.l   d0,IOTV_TIME+TV_MICRO(a1)          ; set the timeout
  1480.      movea.l  SysBase(pc),a6              ; get ExecBase
  1481.      jsr      _LVOSendIO(a6)              ; queue the request
  1482.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1483.      bra      30$                      ; go exit
  1484.      ;
  1485.      ;      Non serial interrupt
  1486.      ;
  1487. level5n:
  1488.      movem.l  d0-d1/a0-a1/a5-a6,-(sp)          ; save registers
  1489.      lea      _custom,a0                  ; get ptr to custom regs
  1490.      move.w   intenar(a0),d1              ; get enabled interrupts
  1491.      and.w      intreqr(a0),d1              ; and in requested interrupts
  1492.      movea.l  SysBase(pc),a6              ; get ExecBase
  1493.      btst      #INTB_DSKSYNC,d1              ; Disk synchronized?
  1494.      beq.b      10$                      ; nope, branch
  1495.      movem.l  IVDSKSYNC(A6),a1/a5              ; get data and code ptrs
  1496.      jsr      (a5)                      ; branch to routine
  1497. 10$     movem.l  (sp)+,d0-d1/a0-a1/a5-a6          ; restore registers
  1498.      rte                          ; return
  1499.      ;
  1500.      ;      Default Level 5 handler
  1501.      ;
  1502. level5:
  1503.      btst      #INTB_INTEN-8,_intenar          ; interrupts enabled?
  1504.      beq.b      45$                      ; nope, ignore
  1505.      btst      #INTB_RBF-8,_intreqr              ; receive buffer full?
  1506.      beq.b      level5n                  ; nope, invoke old handler
  1507.      ;
  1508.      move.l   a0,-(sp)                  ; save registers
  1509.      move.l   a1,-(sp)                  ; save registers
  1510.      lea      _custom,a1                  ; get ptr to custom regs
  1511.      ;
  1512. 10$     btst      #7,serdatr(a1)              ; Overrun?
  1513.      bne.b      50$                      ; yep, branch
  1514.      ;
  1515. 20$     movea.l  i_BufIn(pc),a0              ; get current ptr
  1516.      move.b   serdatr+1(a1),(a0)+              ; store received byte
  1517.      move.w   #INTF_RBF,intreq(a1)              ; clear RBF interrupt
  1518.      addq.l   #1,i_InCnt                  ; incr bytes in buffer
  1519.      ;
  1520.      cmpa.l   i_BufEnd(pc),a0              ; hit end of buffer?
  1521.      beq.b      60$                      ; yep, branch
  1522. 30$     move.l   a0,i_BufIn                  ; store input ptr
  1523.      ;
  1524.      subq.l   #1,i_Thresh                  ; close to full buffer?
  1525.      beq.b      70$                      ; yep, branch
  1526.      ;
  1527. 40$     btst      #INTB_RBF-8,intreqr(a1)          ; receive buffer full?
  1528.      bne.b      10$                      ; yep, go get another byte
  1529.      ;
  1530.      movea.l  (sp)+,a1                  ; restore registers
  1531.      movea.l  (sp)+,a0                  ; restore registers
  1532. 45$     rte                          ; return
  1533.      ;
  1534.      ;      We've missed some data, so set overrun flag.
  1535.      ;
  1536. 50$     addq.b   #1,Overrun                  ; set overrun flag
  1537.      bra.b      20$                      ; continue
  1538.      ;
  1539.      ;      Hit physical end of buffer, so wrap to the start of the buffer.
  1540.      ;
  1541. 60$     movea.l  i_BufPtr(pc),a0              ; get buffer ptr
  1542.      bra.b      30$                      ; continue
  1543.      ;
  1544.      ;      Hit buffer threshold, so tell other end not to send any more
  1545.      ;      data.
  1546.      ;
  1547. 70$     tst.b      Handshake                  ; are we handshaking?
  1548.      beq.b      40$                      ; nope, skip RTS
  1549.      ori.b      #1<<CIAB_COMRTS,_ciabpra          ; block further input
  1550.      bra.b      40$                      ; go return
  1551.      ;
  1552.      ;
  1553.      ;
  1554. level2:
  1555.      ;
  1556.      ;      If there's nothing in the buffer, there's no point in going
  1557.      ;      any further.
  1558.      ;
  1559.      move.l   i_InCnt(pc),d0              ; anything in the buffer?
  1560.      bne.b      20$                      ; yep, branch
  1561. 10$     moveq      #0,d0                   ; set Z flag
  1562.      rts                          ; return
  1563.      ;
  1564.      ;      If we've been "disabled" then get out.
  1565.      ;
  1566. 20$     move.b   disableRead(pc),d0              ; internally disabled?
  1567.      bge.b      10$                      ; yep, get out of here
  1568.      lea.l      Start(pc),a5                  ; get base
  1569.      ;
  1570.      ;      If we have an active request, branch down and try to fulfill it.
  1571.      ;
  1572.      move.l   cr_IOReq(pc),d0              ; get and test active I/O
  1573.      bne.b      30$                      ; nzero, active, branch
  1574.      ;
  1575.      ;      Get first node in list and test if empty.
  1576.      ;
  1577.      move.l   (a1),a0                  ; get head of list
  1578.      move.l   (a0),d0                  ; get successor
  1579.      beq.b      10$                      ; end of list? yep, branch
  1580.      ;
  1581.      ;      Remove the node from the list
  1582.      ;
  1583.      move.l   d0,(a1)                  ; make new head
  1584.      exg.l      d0,a0                   ; swap nodes
  1585.      move.l   a1,LN_PRED(a0)              ; store predecessor
  1586.      ;
  1587.      ;      Setup fields for processing a read request
  1588.      ;
  1589.      movea.l  d0,a1                   ; get I/O request
  1590.      move.b   IO_FLAGS(a1),d1
  1591.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1592.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1593.      move.b   d1,IO_FLAGS(a1)
  1594.      move.l   a1,cr_IOReq-Start(a5)           ; store I/O request
  1595.      move.l   IO_DATA(a1),cr_OutPtr-Start(a5)     ; get/set output ptr
  1596.      move.l   IO_LENGTH(a1),cr_Length-Start(a5)   ; get/set output count
  1597.      ;
  1598.      ;      Process an active I/O request
  1599.      ;
  1600. 30$     movea.l  SysBase(pc),a6              ; get ExecBase
  1601.      move.l   d0,a1                   ; get I/O request
  1602.      bsr.b      copyData                  ; go copy 'em
  1603.      tst.l      d0                      ; done with request?
  1604.      beq.b      10$                      ; nope, branch
  1605.      ;
  1606.      ;      the request has been satisfied, so return it.
  1607.      ;
  1608.      clr.l      cr_IOReq-Start(a5)              ; clear request
  1609.      andi.b   #~(1<<IOSERB_ACTIVE),IO_FLAGS(a1)   ; no longer active
  1610.      DEBUGIO  replyIO
  1611.      jsr      _LVOReplyMsg(a6)              ; return I/O
  1612.      bra.b      10$
  1613.      ;
  1614.      ;      Registers:
  1615.      ;      Entry:   A1        Ptr to I/O Request
  1616.      ;           A6        ExecBase
  1617.      ;      Exit:    D0        ZERO - request not done, do not reply it
  1618.      ;                NZERO - request done, reply it
  1619.      ;
  1620. copyData:
  1621.      ;
  1622.      ;      Process an active I/O request (or fall through from above)
  1623.      ;
  1624.      movem.l  d2-d5/a1-a5,-(sp)              ; save registers
  1625.      lea.l      Start(pc),a5                  ; get base
  1626.      movea.l  a1,a4                   ; get I/O request
  1627.      ;
  1628.      movea.l  i_BufOut(pc),a2              ; get current bufout ptr
  1629.      movea.l  cr_OutPtr(pc),a3              ; get current output ptr
  1630.      move.l   cr_Length(pc),d2              ; get current bytes needed
  1631.      move.l   i_InCnt(pc),d3              ; get current bytes in buffer
  1632.      ;
  1633.      ;      If we don't have enough bytes to satisfy the request,
  1634.      ;      set the length to the number of bytes we do have.
  1635.      ;
  1636.      cmp.l      d2,d3                   ; enuf to satisfy request?
  1637.      bge.b      15$                      ; yep, so branch
  1638.      move.l   d3,d2                   ; # to copy = # in buffer
  1639.      bra.b      15$                      ; branch to loop entry
  1640.      ;
  1641.      ;      Start of copy loop.
  1642.      ;
  1643. 10$     movea.l  i_BufPtr(pc),a2              ; reset bufout to start
  1644.      ;
  1645.      ;      Entry point of copy loop.
  1646.      ;
  1647. 15$     move.l   d2,d3                   ; xfer # of bytes to copy
  1648.      ;
  1649.      ;      If the copy will extend past the end of the buffer, we can
  1650.      ;      only copy the number of bytes to the end this go around.
  1651.      ;
  1652.      move.l   i_BufEnd(pc),d0              ; get ptr to end of buf
  1653.      sub.l      a2,d0                   ; calc # of bytes to end
  1654.      cmp.l      d0,d3                   ; # to copy < # to end?
  1655.      blt.b      20$                      ; yep, branch
  1656.      move.l   d0,d3                   ; get bytes to end
  1657.      ;
  1658.      ;      Registers:
  1659.      ;
  1660.      ;      A2 = pointer from which data will be copied
  1661.      ;      A3 = pointer to which data will be copied
  1662.      ;      D2 = number of bytes that need to be copied
  1663.      ;      D3 = number of bytes to copy this iteration
  1664.      ;
  1665.     IFNE EOFCODE
  1666. 20$     btst      #SERB_EOFMODE,IO_SERFLAGS(a4)       ; EOFMODE requested?
  1667.      beq.b      30$                      ; nope, just go copy
  1668.      ;
  1669.      ;      EOFMODE was specified so copy characters 1 at a time until
  1670.      ;      we hit an EOF character, the output butter has filled, or
  1671.      ;      the input buffer has drained.
  1672.      ;
  1673.      move.l   d3,d0                   ; get length
  1674.      ;
  1675.      lea.l      IO_TERMARRAY(a4),a1              ; get termarry ptr
  1676. 21$     move.b   (a2)+,d1                  ; get byte
  1677.      ; This way the term char IS copied (if the term char is not copied eofmode will fail)
  1678.      move.b   d1,(a3)+                  ; put in output buffer
  1679.      ;
  1680.      cmp.b      (a1),d1                  ; found term char?
  1681.      bge.b      22$                      ; possibly, branch
  1682.      cmp.b      1(a1),d1                  ; found term char?
  1683.      bge.b      22$                      ; possibly, branch
  1684.      cmp.b      2(a1),d1                  ; found term char?
  1685.      bge.b      22$                      ; possibly, branch
  1686.      cmp.b      3(a1),d1                  ; found term char?
  1687.      bge.b      22$                      ; possibly, branch
  1688.      cmp.b      4(a1),d1                  ; found term char?
  1689.      bge.b      22$                      ; possibly, branch
  1690.      cmp.b      5(a1),d1                  ; found term char?
  1691.      bge.b      22$                      ; possibly, branch
  1692.      cmp.b      6(a1),d1                  ; found term char?
  1693.      bge.b      22$                      ; possibly, branch
  1694.      cmp.b      7(a1),d1                  ; found term char?
  1695.      bgt.b      23$                      ; nope, branch
  1696. 22$     beq.b      24$                      ; term char found?
  1697.      ;
  1698.      ;      Didn't find a term character, so continue with the copy loop
  1699.      ;
  1700. 23$
  1701.      subq.l   #1,d0                   ; decr length counter
  1702.      bne.b      21$                      ; continue if more
  1703.      bra      40$                      ; done with copy, branch
  1704.      ;
  1705.      ;      We've found a termination character.
  1706.      ;
  1707. 24$     clr.l      cr_Length-Start(a5)              ; done with request
  1708.      bra      50$                      ; branch
  1709.     ELSE
  1710. 20$
  1711.     ENDC
  1712.      ;
  1713.      ;      EOFMODE not specified, so just do a bulk copy.
  1714.      ;
  1715.      ;      XXX POSSIBLE SPEEDUP XXX
  1716.      ;
  1717.      ;      For short copies it would be quicker to have a simple inline
  1718.      ;      loop, but what's short???  It would be different by CPU.
  1719.      ;
  1720. 30$
  1721.      move.l   d3,d0                   ; get length
  1722.      movea.l  a3,a1                   ; where to put it
  1723.      movea.l  a2,a0                   ; where to get it
  1724.  
  1725.      movem.l  d2-d7/a2-a6,-(sp)
  1726. ; we assume buffers are aligned
  1727. ; NB: buffer size is multiple of 64bytes (not contents size)
  1728. ; Copy should fit on 256 byte Inst Cache.
  1729. ; Copy loop for 1k blocks
  1730. 35$     cmp.l      #1024,d0
  1731.      blo      100$
  1732. ; Copy 1008 bytes
  1733.      movem.l  (a0)+,d1-d7/a2-a6
  1734.      movem.l  d1-d7/a2-a6,(a1)
  1735.      movem.l  (a0)+,d1-d7/a2-a6
  1736.      movem.l  d1-d7/a2-a6,48(a1)
  1737.      movem.l  (a0)+,d1-d7/a2-a6
  1738.      movem.l  d1-d7/a2-a6,96(a1)
  1739.      movem.l  (a0)+,d1-d7/a2-a6
  1740.      movem.l  d1-d7/a2-a6,144(a1)
  1741.      movem.l  (a0)+,d1-d7/a2-a6
  1742.      movem.l  d1-d7/a2-a6,192(a1)
  1743.      movem.l  (a0)+,d1-d7/a2-a6
  1744.      movem.l  d1-d7/a2-a6,240(a1)
  1745.      movem.l  (a0)+,d1-d7/a2-a6
  1746.      movem.l  d1-d7/a2-a6,288(a1)
  1747.      movem.l  (a0)+,d1-d7/a2-a6
  1748.      movem.l  d1-d7/a2-a6,336(a1)
  1749.      movem.l  (a0)+,d1-d7/a2-a6
  1750.      movem.l  d1-d7/a2-a6,384(a1)
  1751.      movem.l  (a0)+,d1-d7/a2-a6
  1752.      movem.l  d1-d7/a2-a6,432(a1)
  1753.      movem.l  (a0)+,d1-d7/a2-a6
  1754.      movem.l  d1-d7/a2-a6,480(a1)
  1755.      movem.l  (a0)+,d1-d7/a2-a6
  1756.      movem.l  d1-d7/a2-a6,528(a1)
  1757.      movem.l  (a0)+,d1-d7/a2-a6
  1758.      movem.l  d1-d7/a2-a6,576(a1)
  1759.      movem.l  (a0)+,d1-d7/a2-a6
  1760.      movem.l  d1-d7/a2-a6,624(a1)
  1761.      movem.l  (a0)+,d1-d7/a2-a6
  1762.      movem.l  d1-d7/a2-a6,672(a1)
  1763.      movem.l  (a0)+,d1-d7/a2-a6
  1764.      movem.l  d1-d7/a2-a6,720(a1)
  1765.      movem.l  (a0)+,d1-d7/a2-a6
  1766.      movem.l  d1-d7/a2-a6,768(a1)
  1767.      movem.l  (a0)+,d1-d7/a2-a6
  1768.      movem.l  d1-d7/a2-a6,816(a1)
  1769.      movem.l  (a0)+,d1-d7/a2-a6
  1770.      movem.l  d1-d7/a2-a6,864(a1)
  1771.      movem.l  (a0)+,d1-d7/a2-a6
  1772.      movem.l  d1-d7/a2-a6,912(a1)
  1773.      movem.l  (a0)+,d1-d7/a2-a6
  1774.      movem.l  d1-d7/a2-a6,960(a1)
  1775. ; Copy 16 bytes
  1776.      movem.l  (a0)+,d1-d4
  1777.      movem.l  d1-d4,1008(a1)
  1778.      lea.l      1024(a1),a1
  1779.      sub.l      #1024,d0
  1780.      bne      35$
  1781.      bra.b      105$
  1782. 100$     move.l   SysBase(pc),a6
  1783.      jsr      _LVOCopyMem(a6)              ; copy it
  1784. 105$     movem.l  (sp)+,d2-d7/a2-a6
  1785.      adda.l   d3,a2                   ; update bufout
  1786.      adda.l   d3,a3                   ; update outptr
  1787.      ;
  1788.      ;      Fall through and entered from EOFMODE loop
  1789.      ;
  1790.      ;      If the following calculation results in a value greater than
  1791.      ;      zero, then we have a buffer wrap and need to process the
  1792.      ;      remaining bytes at the beginning of the buffer.
  1793.      ;
  1794. 40$     sub.l      d3,d2                   ; calc bytes left to copy
  1795.      bgt      10$                      ; >0, more to copy, branch
  1796.      ;
  1797.      ;
  1798.      ;
  1799. 50$     move.l   a3,d1                   ; get outptr
  1800.      sub.l      cr_OutPtr(pc),d1              ; calc length
  1801.      move.l   a3,cr_OutPtr-Start(a5)          ; update outptr
  1802.      ;
  1803.      ;      Update output ptr and I/O request
  1804.      ;
  1805.      move.l   a2,i_BufOut-Start(a5)           ; store bufout ptr
  1806.      add.l      d1,IO_ACTUAL(a4)              ; update I/O request
  1807.      ;
  1808.      ;      Update number of bytes left in the buffer.
  1809.      ;
  1810.      sub.l      d1,i_InCnt-Start(a5)              ; calc bytes left in buffer
  1811.      ;
  1812.      ;      If the threshold becomes positive here, then, if requested,
  1813.      ;      tell the other end that it's okay to start sending more data.
  1814.      ;
  1815.      add.l      d1,i_Thresh-Start(a5)           ; calc thresh and test
  1816.      ble.b      60$                      ; <= 0, need more data, skip
  1817.      tst.b      Handshake-Start(a5)              ; are we handshaking?
  1818.      beq.b      60$                      ; nope, skip RTS
  1819.      andi.b   #~(1<<CIAB_COMRTS),_ciabpra            ; ready to receive more data
  1820.      ;
  1821.      ;      Set error if we've had any overruns.
  1822.      ;
  1823. 60$     tst.b      Overrun-Start(a5)              ; did overrun occur?
  1824.      beq.b      70$                      ; nope, branch
  1825.      clr.b      Overrun-Start(a5)              ; reset overrun flag
  1826.      move.b   #SerErr_LineErr,IO_ERROR(a4)          ; set error code
  1827.      ;
  1828.      ;      Calc number of bytes left to copy.  If the result is greater
  1829.      ;      than zero, then we have more to copy so return an incomplete
  1830.      ;      status.
  1831.      ;
  1832. 70$     moveq      #0,d0                   ; assume I/O incomplete
  1833.      sub.l      d1,cr_Length-Start(a5)          ; update length and test
  1834.      bgt.b      90$                      ; >0, more to do, branch
  1835.      ;
  1836.      ;      We've completed the I/O request either by copying the requested
  1837.      ;      of bytes or by finding an EOFMODE character, so return a "reply"
  1838.      ;      status.
  1839.      ;
  1840.      moveq      #1,d0                   ; indicate reply
  1841.      ;
  1842.      ;      Restore and exit
  1843.      ;
  1844. 90$     movem.l  (sp)+,d2-d5/a1-a5              ; restore registers
  1845.      rts                          ; return (status in D0)
  1846.      ;
  1847.      ;      Align data
  1848.      ;
  1849.      CNOP      0,4
  1850.      ;
  1851.      ;
  1852.      ;
  1853. Init:
  1854.      DC.L      sizeof_Base8n1
  1855.      DC.L      funcTab
  1856.      DC.L      dataTab
  1857.      DC.L      InitRoutine
  1858.      ;
  1859.      ;
  1860.      ;
  1861. funcTab:
  1862.      DC.W      -1
  1863.      DC.W      dev_Open-funcTab
  1864.      DC.W      dev_Close-funcTab
  1865.      DC.W      dev_Expunge-funcTab
  1866.      DC.W      dev_Null-funcTab
  1867.      DC.W      dev_BeginIO-funcTab
  1868.      DC.W      dev_AbortIO-funcTab
  1869.      DC.W      -1
  1870.      ;
  1871.      ;
  1872.      ;
  1873. dataTab:
  1874.      INITBYTE LN_TYPE,NT_DEVICE
  1875.      INITLONG LN_NAME,Name
  1876.      INITBYTE LIB_FLAGS,LIBF_SUMUSED|LIBF_CHANGED
  1877.      INITWORD LIB_VERSION,VERSION
  1878.      INITWORD LIB_REVISION,REVISION
  1879.      INITLONG LIB_IDSTRING,IdString
  1880.      DC.W      0
  1881.      ;
  1882.      ;      String Constants
  1883.      ;
  1884. miscresource:
  1885.      DC.B      "misc.resource",0
  1886. timerdevice:
  1887.      DC.B      "timer.device",0
  1888. intuitlib:
  1889.      DC.B      "intuition.library",0
  1890. Name:
  1891.      DC.B      "8n1.device",0
  1892. IdString:
  1893.      VSTRING
  1894.      ;
  1895.      ;      End of checksummed area.  (Realigns data too!)
  1896.      ;
  1897. ENDTag:
  1898.      CNOP      0,4
  1899.      ;
  1900.      ;      Global SysBase (Use instead of AbsExecBase for speed)
  1901.      ;
  1902. SysBase:
  1903.      DC.L      0
  1904.      ;
  1905.      ;      Internal buffer tracking (DO NOT CHANGE THE ORDER!!!!)
  1906.      ;
  1907. i_BufPtr:
  1908.      DC.L      0
  1909. i_BufIn:
  1910.      DC.L      0
  1911. i_BufOut:
  1912.      DC.L      0
  1913. i_BufEnd:
  1914.      DC.L      0
  1915. i_InCnt:
  1916.      DC.L      0
  1917. i_Thresh:
  1918.      DC.L      0
  1919.      ;
  1920.      ;      Used while processing a read request.
  1921.      ;
  1922. cr_IOReq:
  1923.      DC.L      0
  1924. cr_OutPtr:
  1925.      DC.L      0
  1926. cr_Length:
  1927.      DC.L      0
  1928.      ;
  1929.      ;      List head for read requests
  1930.      ;
  1931. readQ:
  1932.      DC.L      readQ+MLH_TAIL
  1933.      DC.L      0
  1934.      DC.L      readQ
  1935.      ;
  1936.      ;      Write control.
  1937.      ;
  1938. cw_Length:
  1939.      DC.L      0
  1940. cw_Buffer:
  1941.      DC.L      0
  1942. cw_IOReq:
  1943.      DC.L      0
  1944.      ;
  1945.      ;      List head for write requests
  1946.      ;
  1947. writeQ:
  1948.      DC.L      writeQ+MLH_TAIL
  1949.      DC.L      0
  1950.      DC.L      writeQ
  1951.      ;
  1952.      ;
  1953.      ;
  1954. timerPort:
  1955.      DC.L      0                      ; LN_SUCC
  1956.      DC.L      0                      ; LN_PRED
  1957.      DC.B      NT_MSGPORT                  ; LN_TYPE
  1958.      DC.B      0                      ; LN_PRI
  1959.      DC.L      0                      ; LN_NAME
  1960.      DC.B      3                      ; MP_FLAGS (undoc'ed)
  1961.      DC.B      0                      ; MP_SIGBIT
  1962.      DC.L      timerRtn                  ; MP_SIGTASK
  1963.      DC.L      timerPort+MP_MSGLIST+LH_TAIL          ; LH_HEAD
  1964.      DC.L      0                      ; LH_TAIL
  1965.      DC.L      timerPort+MP_MSGLIST              ; LH_TAILPRED
  1966.      DC.B      0                      ; LH_TYPE
  1967.      DC.B      0                      ; LH_pad
  1968.      DC.W      0                      ; long align
  1969.      ;
  1970.      ;
  1971.      ;
  1972. timerReq:
  1973.      DC.L      0                      ; LN_SUCC
  1974.      DC.L      0                      ; LN_PRED
  1975.      DC.B      NT_MESSAGE                  ; LN_TYPE
  1976.      DC.B      0                      ; LN_PRI
  1977.      DC.L      0                      ; LN_NAME
  1978.      DC.L      timerPort                  ; MN_REPLYPORT
  1979.      DC.W      IOTV_SIZE                  ; MN_LENGTH
  1980.      DC.L      0                      ; IO_DEVICE
  1981.      DC.L      0                      ; IO_UNIT
  1982.      DC.W      TR_ADDREQUEST               ; IO_COMMAND
  1983.      DC.B      0                      ; IO_FLAGS
  1984.      DC.B      0                      ; IO_ERROR
  1985.      DC.L      0                      ; TV_SECS
  1986.      DC.L      0                      ; TV_MICROS
  1987.      ;
  1988.      ;
  1989.      ;
  1990. VBInterrupt:
  1991.      DC.L      0                      ; LN_SUCC
  1992.      DC.L      0                      ; LN_PRED
  1993.      DC.B      NT_INTERRUPT                  ; LN_TYPE
  1994.      DC.B      0                      ; LN_PRI
  1995.      DC.L      Name                      ; LN_NAME
  1996.      DC.L      readQ                   ; IS_DATA
  1997.      DC.L      level2                  ; IS_CODE
  1998.      ;
  1999.      ;      Global flags
  2000.      ;
  2001. Overrun:
  2002.      DC.B      0
  2003. Handshake:
  2004.      DC.B      1
  2005. disableRead:
  2006.      DC.B      -1
  2007.      ;
  2008.      ;
  2009.      ;
  2010.      END
  2011.  
  2012.